<?php

/**
 * ExtJavaScriptObject class file
 *
 * @author TrueSoftware B.V. (The Netherlands)
 * @link http://www.ext4yii.com
 * @copyright Copyright 2007-2010 TrueSoftwareB.V. all rights reserved.
 * @license http://www.ext4yii.com/license/
 *          EVALUATION VERSION - NOT FOR COMMERCIAL USE OR DISTRIBUTION.
 * @version 0.7.2
 */

/**
 * ExtJavaScriptObject provides functionality to create an object which can be
 * rendered to a JavaScript object notation. This class is mostly used internally.
 * <p>Usage:</p>
 * <ext:Code brush="php">
 * <?php
 *      $jso = new ExtJavaScriptObject();
 *      $jso->addArray('margin',aray(1,2,3,4));
 *      $jso->addBoolean('active',true);
 *      $jso->addFunction('sayHello','name','alert(name)');
 *      $jso->addString('id',1024);
 *      echo $jso->render();
 * ?>
 * </ext:Code>
 */
class ExtJavaScriptObject
{

    private $_members = array();

    /**
     * internally renders an array
     * @param array $data
     * @return string a string as a JavaScript array 
     */
    private function renderArray($data)
    {
        $result = array();
        foreach ($data as $item)
        {
            if (is_null($item))
                $item = 'null';
            elseif (is_bool($item))
                $item = $item ? 'true' : 'false';
            elseif (is_string($item))
            {
                $test = explode('js://', '+' . $item);
                if (count($test) >= 2 && ($test[0] == '+'))
                    $item = preg_replace('/js:\/\//si', '', $item, 1);
                else
                    $item='"' . str_replace('"', '\"', $item) . '"';
            }
            elseif (is_array($item))
                $item = $this->renderArray($item);
            elseif ($item instanceof ExtJavaScriptObject)
                $item = $item->render();

            $result[] = $item;
        }
        return '[' . implode(',', $result) . ']';
    }

    /**
     * @view
     * This function adds an array to the JavaScript object. If the given $data is
     * not an array then the value is converted to null
     * @param string $name the JavaScript object property name
     * @param array $data a PHP array which can be converted to a JavaScript array
     */
    public function addArray($name, $data)
    {
        if (is_array($data))
            $this->addMember($name, $this->renderArray($data));
        else
            $this->addMember($name, 'null');
    }

    /**
     * @view
     * This function adds a boolean value to the JavaScript object
     * @param string $name the JavaScript object property name
     * @param boolean $data a boolean value
     */
    public function addBoolean($name, $data)
    {
        $this->addMember($name, ($data == true ? 'true' : 'false'));
    }

    /**
     * @view
     * This function adds a string value to the JavaScript object
     * @param string $name the JavaScript object property name
     * @param string $data a string value
     */
    public function addString($name, $data)
    {
        $this->addMember($name, '"' . str_replace('"', '\"', $data) . '"');
    }

    /**
     * @view
     * This function adds a JavaScriptObject to the JavaScript object
     * @param string $name the JavaScript object property name
     * @param JavaScriptObject $object a JavaScriptObject object
     */
    public function addJavaScriptObject($name, $object)
    {
        if (is_null($object))
            $this->addMember($name, 'null');
        else
            $this->addMember($name, $object->render());
    }

    /**
     * @view
     * This method adds a function to the JavaScript object
     * @param string $name the JavaScript object function name
     * @param string $args the function arguments (eg. (foo,bar)
     * @param string $body the body of the function
     */
    public function addFunction($name, $args, $body)
    {
        if (is_array($args))
            $args = implode(',', $args);

        $this->addMember($name, sprintf('function(%s){ %s }', $args, $body));
    }

    /**
     * @view
     * This function adds a generic JavaScript property
     * @param string $name the JavaScript object property name
     * @param string $rawdata a raw string containg the property body
     */
    public function addMember($name, $rawdata)
    {
        $this->_members[$name] = $rawdata;
    }

    /**
     * @view
     * This function renders the JavaScript object to a JavaScript notation
     * @return string as a JavaScript object
     */
    public function render()
    {
        $result = array();
        foreach ($this->_members as $name => $data)
            $result[] = $name . ':' . $data;
        return '{' . implode(',', $result) . '}';
    }

}

?>
